﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

using Steering.Robot;
using System.Timers;
using System.Windows.Threading;
using System.Threading;
using Steering.SteeringAbstraction;

namespace Virtix
{
    internal delegate void SwitchToDelegate(bool closeHud);

    /// <summary>
    /// Interaction logic for HUD.xaml
    /// </summary>
    public partial class HUD : Window
    {
        #region Fields and constants

        private const string STEERING_NAME_WHEEL = "SteeringWheel";
        private const string STEERING_NAME_GLOVE = "Glove";
        private const string STEERED_NAME_SIMULATION = "Simulation";
        private const string STEERED_NAME_ROBOT = "Robot";

        private Menu menu;

        private ForkliftControl forklift;
        private VideoPlayer videoPlayer;

        private SwitchToDelegate switchToMenu;

        #endregion

        #region Public methods

        /// <summary>
        /// Initializes the HUD window. Start() needs to be called for it to actually start working.
        /// </summary>
        /// <param name="menu">Menu window.</param>
        /// <param name="steeringSourceType"></param>
        /// <param name="robotControlType"></param>
        /// <param name="transmitterIp"></param>
        /// <param name="comPort"></param>
        public HUD(Menu menu, string steeringSourceType, string robotControlType, string transmitterIp, byte comPort)
        {
            InitializeComponent();
            this.menu = menu;
            switchToMenu = menu.SwitchTo;

            ForkliftSteeringSource steeringSource = CreateSteeringSource(steeringSourceType);
            RobotControl robotControl = CreateRobotControl(robotControlType, comPort);
            this.forklift = new ForkliftControl(steeringSource, robotControl,
                new EventHandler(forklift_StopIssued), new EventHandler(forklift_MenuIssued));
            
            SetBindings();
            videoPlayer = new VideoPlayer(hudCanvas, transmitterIp);
        }

        /// <summary>
        /// HUD connects all adapters, makes necessary connections and starts working.
        /// </summary>
        public void Start()
        {
            SwitchTo(); 
            this.forklift.Start();
            videoPlayer.Start();    // starting video
        }

        /// <summary>
        /// Releases all recources and closes all connections;
        /// </summary>
        public void Destroy()
        {
            this.forklift.Stop(); // stop robot
            this.simulationCanvas.Children.Clear();

            this.videoPlayer.Stop(); // stopping video
        }

        /// <summary>
        /// Switches from menu to HUD window.
        /// </summary>
        public void SwitchTo()
        {
            App.Current.MainWindow = this;
            menu.Hide();
            this.Show();
            this.forklift.IsActive = true;
        }

        #endregion

        #region Private utility methods

        /// <summary>
        /// Creates a RobotControl object of type selected in the appropriate comboBox.
        /// </summary>
        /// <param name="controlTypeName">Name of the specific RobotControl type.</param>
        /// <param name="comPort"></param>
        /// <returns>Initialized RobotControl object of desired type.</returns>
        private RobotControl CreateRobotControl(string controlTypeName, byte comPort)
        {
            if (controlTypeName.Equals(STEERED_NAME_SIMULATION))
            {
                double width = System.Windows.SystemParameters.PrimaryScreenWidth - Canvas.GetLeft(this.simulationCanvas);
                double height = System.Windows.SystemParameters.PrimaryScreenHeight - Canvas.GetTop(this.simulationCanvas);

                SimulationControl robotControl = new SimulationControl(width, height);
                this.simulationCanvas.Children.Add(robotControl.RobotSimulation);

                return robotControl;
            }
            else
            {
                return new MindsquallsControl(comPort);
            }
        }

        private ForkliftSteeringSource CreateSteeringSource(string steeringTypeName)
        {
            if (steeringTypeName.Equals(STEERING_NAME_GLOVE))
            {
                return new GloveAdapter.GloveSteering();
            }
            else
            {
                return new SteeringWheelAdapter.WheelSteering();
            }
        }
        
        /// <summary>
        /// Sets bindings between HUD controls and adapters.
        /// </summary>
        private void SetBindings()
        {
            DataContext = forklift.SteeringSource;
            BindingMode bindingMode = BindingMode.TwoWay;
            speedSlider.SetBinding(Slider.ValueProperty, new Binding("Speed.Value") { Mode = bindingMode });
            turnSlider.SetBinding(Slider.ValueProperty, new Binding("Turn.Value") { Mode = bindingMode });
            forkSlider.SetBinding(Slider.ValueProperty, new Binding("ForkSpeed.Value") { Mode = bindingMode });
        }

        private void SetTextToDebugTextbox(string text)
        {
            menu.debugTextBox.Text = text;
        }

        private void AddTextToDebugTextbox(string text)
        {
            menu.debugTextBox.Text += text;
        }

        #endregion

        #region Event handling

        /// <summary>
        /// Switches back to menu window.
        /// </summary>
        private void Window_Closed(object sender, EventArgs e)
        {
            menu.SwitchTo(true);
        }

        /// <summary>
        /// Returns to menu window and stops the forklift.
        /// </summary>
        void forklift_MenuIssued(object sender, EventArgs e)
        {
            this.forklift.IsActive = false;
            this.forklift.Halt();
            this.Dispatcher.Invoke(switchToMenu, false);
            //menu.SwitchTo(false);
        }

        /// <summary>
        /// Stops the forklift.
        /// </summary>
        void forklift_StopIssued(object sender, EventArgs e)
        {
            this.forklift.Halt();
        }

        /// <summary>
        /// DEBUG
        /// </summary>
        private void sensorLightBox_Checked(object sender, RoutedEventArgs e)
        {
            //nxt2Adapter.NxtLightSensorGenerateLight = (bool)sensorLightBox.IsChecked;
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            this.forklift.Halt();
            menu.SwitchTo(false);
        }


        // nie wiem czy sa potrzenbne - sa w xaml'u
        private void Window_Loaded(object sender, EventArgs e) { }
        private void mainSteeringBox_Checked(object sender, EventArgs e) { }
        private void secondarySteeringBox_Checked(object sender, EventArgs e) { }

        private void BackToMenu_Click(object sender, EventArgs e)
        {
            this.Destroy();
        }

        #endregion
    }
}
